CentOS 7
Sponsored Link

SQL Server 2017 : Read Scale-out Availability Group
2017/10/17
 
Configure Read Scale-out Availability Group.
This example is based on the environment like follows.
Configure 3 servers to create a cluster, one is a Primary node and other two nodes are secondary with read-only access.
-----------+-----------------------------+-----------------------------+------------
           |10.0.0.51                    |10.0.0.52                    |10.0.0.53
+----------+-----------+      +----------+-----------+      +----------+-----------+
| [ node01.srv.world ] |      | [ node02.srv.world ] |      | [ node03.srv.world ] |
|      (Primary)       |      |      (Secondary)     |      |      (Secondary)     |
|      SQL Server      |      |       SQL Server     |      |       SQL Server     |
+----------------------+      +----------------------+      +----------------------+

[1]
[2] Enable Always On Availability Group and create a user for mirroring on all nodes.
Replace 'password' to strong one.
[root@node01 ~]#
/opt/mssql/bin/mssql-conf set hadr.hadrenabled 1

SQL Server needs to be restarted in order to apply this setting. Please run
'systemctl restart mssql-server.service'.
[root@node01 ~]#
systemctl restart mssql-server

[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:
1> alter event session AlwaysOn_health on server with (startup_state=on);
2> go
1> create login dbm_login with password = 'password';
2> create user dbm_user for login dbm_login;
3> go
1> exit
[3] Create certificates on Primary node and copy them to other secondary nodes.
Replace 'password', 'pvk_password' to strong one.
[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:
1> create master key encryption by password = 'password';
2> create certificate dbm_certificate with subject = 'dbm';
3> backup certificate dbm_certificate
4> to file = '/var/opt/mssql/data/dbm_certificate.cer'
5> with private key (
6> file = '/var/opt/mssql/data/dbm_certificate.pvk',
7> encryption by password = 'pvk_password'
8> );
9> go
1> exit

[root@node01 ~]#
cd /var/opt/mssql/data

[root@node01 data]#
scp dbm_certificate.* root@node02.srv.world:/var/opt/mssql/data/

root@node02.srv.world's password:
dbm_certificate.cer                           100%  667   614.7KB/s   00:00
dbm_certificate.pvk                           100% 1212     1.0MB/s   00:00
[root@node01 data]#
scp dbm_certificate.* root@node03.srv.world:/var/opt/mssql/data/

root@node03.srv.world's password:
dbm_certificate.cer                           100%  667   581.6KB/s   00:00
dbm_certificate.pvk                           100% 1212   935.1KB/s   00:00
[root@node01 data]#
ssh root@node02.srv.world 'chown mssql. /var/opt/mssql/data/dbm_certificate.*'

[root@node01 data]#
ssh root@node03.srv.world 'chown mssql. /var/opt/mssql/data/dbm_certificate.*'

[4] Create certificates on all secondary nodes.
Replace 'password' to strong one.
For 'pvk_password', specify the same password you set on Primary node above.
[root@node02 ~]#
sqlcmd -S localhost -U SA

Password:
1> create master key encryption by password = 'password';
2> create certificate dbm_certificate authorization dbm_user
3> from file = '/var/opt/mssql/data/dbm_certificate.cer'
4> with private key (
5> file = '/var/opt/mssql/data/dbm_certificate.pvk',
6> decryption by password = 'pvk_password'
7> );
8> go
1> exit
[5] Set Endpoint for mirroring on all nodes.
[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:
1> create endpoint [Hadr_endpoint]
2> as tcp (listener_ip = (0.0.0.0), listener_port = 5022)
3> for data_mirroring (
4> role = all,
5> authentication = certificate dbm_certificate,
6> encryption = required algorithm aes
7> );
8> alter endpoint [Hadr_endpoint] state = started;
9> grant connect on endpoint::[Hadr_endpoint] to [dbm_login];
10> go
1> exit

# if Firewalld is running, allow the port

[root@node01 ~]#
firewall-cmd --add-port=5022/tcp --permanent

[root@node01 ~]#
firewall-cmd --reload

[6] Create Availability Group on primary node.
[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:
1> create availability group [AG01]
2> with (cluster_type = none)
3> for replica on
4> N'node01' with (
5> endpoint_url = N'tcp://10.0.0.51:5022',
6> availability_mode = asynchronous_commit,
7> failover_mode = manual,
8> seeding_mode = automatic,
9> primary_role (read_only_routing_list=(('node02','node03'), 'node01')),
10> secondary_role (
11> allow_connections = read_only,
12> read_only_routing_url = N'tcp://10.0.0.51:1433')
13> ),
14> N'node02' with (
15> endpoint_url = N'tcp://10.0.0.52:5022',
16> availability_mode = asynchronous_commit,
17> failover_mode = manual,
18> seeding_mode = automatic,
19> primary_role (read_only_routing_list=(('node01','node03'), 'node02')),
20> secondary_role (
21> allow_connections = read_only,
22> read_only_routing_url = N'tcp://10.0.0.52:1433')
23> ),
24> N'node03' with (
25> endpoint_url = N'tcp://10.0.0.53:5022',
26> availability_mode = asynchronous_commit,
27> failover_mode = manual,
28> seeding_mode = automatic,
29> primary_role (read_only_routing_list=(('node01','node02'), 'node03')),
30> secondary_role (
31> allow_connections = read_only,
32> read_only_routing_url = N'tcp://10.0.0.53:1433')
33> );
34> alter availability group [AG01] grant create any database;
35> go
1> exit
[7] Join in Availability Group on all secondary nodes.
[root@node02 ~]#
sqlcmd -S localhost -U SA

Password:
1> alter availability group [AG01] join with (cluster_type = none);
2> alter availability group [AG01] grant create any database;
3> go
1> exit
[8] Add Listener and Database to Availability Group on primary node.
[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:
1> alter availability group [AG01] add listener 'AG01_listener'
2> ( with ip (
3> ('10.0.0.51', '255.255.255.0'),
4> ('10.0.0.52', '255.255.255.0'),
5> ('10.0.0.53', '255.255.255.0') ),
6> port = 1433
7> );
8> go
1> create database [AG01_DB];
2> alter database [AG01_DB] set recovery full;
3> backup database [AG01_DB] to disk = N'/var/opt/mssql/data/AG01_DB.bak';
4> alter availability group [AG01] add database [AG01_DB];
5> go
Processed 304 pages for database 'AG01_DB', file 'AG01_DB' on file 1.
Processed 3 pages for database 'AG01_DB', file 'AG01_DB_log' on file 1.
BACKUP DATABASE successfully processed 307 pages in 0.163 seconds (14.714 MB/sec).
1> exit

# verify possible to see the database on secondary nodes

[root@node01 ~]#
sqlcmd -S node02 -U SA -Q 'select name, create_date from sys.databases where name = "AG01_DB"'

Password:
name                         create_date
---------------------------- -----------------------
AG01_DB                      2017-10-18 19:20:18.740

(1 rows affected)
[9] It's OK all. Verify it works normally to access to the listener and database.
[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:

# current state
1> select L.replica_id,L.replica_server_name,R.role_desc from sys.availability_replicas as L
2> left join sys.dm_hadr_availability_replica_states as R on L.replica_id = R.replica_id
3> go
replica_id                           replica_server_name     role_desc
------------------------------------ ----------------------- ----------------
ACDB4168-C9FD-493F-89C0-FBE067E85BA5 node01                  PRIMARY
E8B30CD1-BB51-4314-AC39-C3326ECA67C2 node02                  SECONDARY
A08550D5-BD92-4A4A-9678-9CC962E37431 node03                  SECONDARY

(3 rows affected)
1> exit

[root@node01 ~]#
sqlcmd -S 10.0.0.51 -U SA -K readonly -d AG01_DB -Q 'select @@servername'

Password:
-------------
node03

(1 rows affected)
[root@node01 ~]#
sqlcmd -S 10.0.0.51 -U SA -K readonly -d AG01_DB -Q 'select @@servername'

Password:
-------------
node02

(1 rows affected)
[root@node01 ~]#
sqlcmd -S 10.0.0.51 -U SA -K readonly -d AG01_DB -Q 'select @@servername'

Password:
--------------
node03

(1 rows affected)

# if access to secondary nodes not with read-only, it is denied like follows

[root@node01 ~]#
sqlcmd -S 10.0.0.52 -U SA -d AG01_DB -Q 'select @@servername'

Password:
Sqlcmd: Error: Microsoft ODBC Driver 13 for SQL Server : The target database ('AG01_DB') is in an availability 
group and is currently accessible for connections when the application intent is set to read only. 
For more information about application intent, see SQL Server Books Online..
[10] If you'd like to switch primary to another node, run like follows.
For example, make node02 be primary.
[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:

# current state
1> select L.replica_id,L.replica_server_name,R.role_desc from sys.availability_replicas as L
2> left join sys.dm_hadr_availability_replica_states as R on L.replica_id = R.replica_id
3> go
replica_id                           replica_server_name     role_desc
------------------------------------ ----------------------- ----------------
ACDB4168-C9FD-493F-89C0-FBE067E85BA5 node01                  PRIMARY
E8B30CD1-BB51-4314-AC39-C3326ECA67C2 node02                  SECONDARY
A08550D5-BD92-4A4A-9678-9CC962E37431 node03                  SECONDARY

(3 rows affected)

# change availability_mode
1> alter availability group [AG01] modify replica
2> on N'node01' with (availability_mode = synchronous_commit);
3> go

1> alter availability group [AG01] modify replica
2> on N'node02' with (availability_mode = synchronous_commit);
3> go

1> alter availability group [AG01] modify replica
2> on N'node03' with (availability_mode = synchronous_commit);
3> go

# change role to secondary
1> alter availability group [AG01] set (role = secondary);
2> go

1> exit

# move to the node you'd like to make it primary and run failover

[root@node02 ~]#
sqlcmd -S localhost -U SA

Password:
1> alter availability group [AG01] force_failover_allow_data_loss;
2> go

# change availability_mode
1> alter availability group [AG01] modify replica
2> on N'node01' with (availability_mode = asynchronous_commit);
3> go

1> alter availability group [AG01] modify replica
2> on N'node02' with (availability_mode = asynchronous_commit);
3> go

1> alter availability group [AG01] modify replica
2> on N'node03' with (availability_mode = asynchronous_commit);
3> go

# go to all secondary nodes and resume database mirroring

[root@node01 ~]#
sqlcmd -S localhost -U SA

Password:
1> alter database [AG01_DB] set hadr resume;
2> go

# goto primary node and show current state

[root@node02 ~]#
sqlcmd -S localhost -U SA

Password:
1> select L.replica_id,L.replica_server_name,R.synchronization_state_desc,R.synchronization_health_desc
1> from sys.availability_replicas as L
2> left join sys.dm_hadr_database_replica_states as R on L.replica_id = R.replica_id
3> go
replica_id                           replica_server_name  synchronization_state_desc  synchronization_health_..
------------------------------------ -------------------- --------------------------- -------------------------
ACDB4168-C9FD-493F-89C0-FBE067E85BA5 node01               SYNCHRONIZING               HEALTHY
E8B30CD1-BB51-4314-AC39-C3326ECA67C2 node02               SYNCHRONIZED                HEALTHY
A08550D5-BD92-4A4A-9678-9CC962E37431 node03               SYNCHRONIZING               HEALTHY

(3 rows affected)
[11] It's possible to verify or change state of [Always On AG] with SSMS on Windows client.
 
Tweet